home *** CD-ROM | disk | FTP | other *** search
/ Compendium Deluxe 1 / LSD Compendium Deluxe 1.iso / a / text / manipulation / cv.lha / cv / cvt / main.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-31  |  14.9 KB  |  642 lines

  1. /*                                                               -*- C -*-
  2.  *  MAIN.C
  3.  *
  4.  *  (c)Copyright 1991-93 by Tobias Ferber,  All Rights Reserved
  5.  */
  6.  
  7. #include <stdarg.h>
  8. #include <string.h>
  9. #include <stdlib.h>
  10. #include <stdio.h>
  11.  
  12. #include "cvt.h"
  13. #include "filecopy.h"
  14.  
  15.  
  16. /*** / GLOBALS / ***/
  17.  
  18. int global_numchars= 256;   /* #of different chars in the local charset.
  19.                              * This number is also used to decide whether
  20.                              * an octal character code in a string runs
  21.                              * out of range */
  22.  
  23. int global_maxhexdigits= 2; /* max. #of hexadecimal digits needed to express
  24.                              * 'global_numchars' */
  25. int global_maxoctdigits= 3; /* max. #of octal digits needed to express
  26.                              * 'global_numchars */
  27.  
  28. int global_numerrors= 0;    /* global error counter */
  29. int global_maxerrors= 5;    /* #of errors until we abort */
  30. int global_checkexists= 0;  /* flag for read_flist() */
  31. char *whoami;               /* copy of argv[0] */
  32.  
  33. /* input, output and error stream */
  34. FILE *fin, *fout, *ferr;
  35.  
  36. #ifdef DEBUG
  37. int debuglevel;
  38. #endif
  39.  
  40. static void display_version_information(void)
  41. {
  42.   puts("CVT Version " VERSION " (compiled " __DATE__ ", " __TIME__ ")\n"
  43.        "(c)Copyright 1991-93 by Tobias Ferber,  All Rights Reserved.\n");
  44. }
  45.  
  46.  
  47. /*** / MAIN / ***/
  48.  
  49. void main(int argc, char *argv[])
  50. {
  51.   char *rulefile, *outfmt, *errfile, *tmpfile;
  52.  
  53.   int badopt, err, dryrun, silent;
  54.   fnode_t *fn;
  55.  
  56. #ifdef _DCC /* Dice */
  57.   expand_args(argc,argv, &argc,&argv);
  58. #endif /* _DCC */
  59.  
  60.   /* initialize globals */
  61.  
  62.   rulefile= outfmt= errfile= tmpfile= (char *)0L;
  63.   badopt= err= dryrun= silent= 0;
  64.  
  65. #ifdef __MSDOS__
  66.  
  67.   /* filenames on MS-DOG systems look very ugly: all uppercase and
  68.    * backslashes.  Perform some cosmetics. */
  69.  
  70.   whoami= "cvt";
  71.  
  72. #else /* !__MSDOS__ */
  73.   whoami= argv[0];
  74.  
  75. #endif /* __MSDOS__ */
  76.  
  77.   fin  = stdin;
  78.   fout = stdout;
  79.   ferr = stderr;
  80.  
  81.   while(--argc>0 && !badopt)
  82.   {
  83.     char *arg= *++argv;
  84.  
  85.     if(*arg=='-')
  86.     {
  87.       if(arg[1]=='-')
  88.         arg= convert_args(*argv);
  89.  
  90.       switch(*++arg)
  91.       {
  92.  
  93. /*-c*/  case 'c':
  94.           if(arg[1]) ++arg;
  95.           else arg= (--argc > 0) ? *(++argv) : (char *)0L;
  96.  
  97.           if(arg && *arg)
  98.           { int r= atoi(arg);
  99.             if(0<r) global_numchars= r;
  100.             else echo("iIllegal charset size: %d"
  101.                        " (using `-c%d')",r,global_numchars);
  102.  
  103.             global_maxhexdigits= numdigits(global_numchars, 0x10);
  104.             global_maxoctdigits= numdigits(global_numchars, 010);
  105.           }
  106.           else
  107.           { echo("missing charset size after `%s' option",*argv);
  108.             ++badopt;
  109.           }
  110.           break;
  111.  
  112. /*-d*/  case 'd':
  113.  
  114.           if(arg[1]) ++arg;
  115.           else arg= (--argc > 0) ? *(++argv) : (char *)0L;
  116.  
  117. #ifdef DEBUG
  118.           if(arg && *arg)
  119.           { debuglevel= atoi(arg);
  120.             if(debuglevel < 0 || debuglevel > 4)
  121.             { echo("debug level %d is not in [0..4].  (using `-d1')",
  122.                 debuglevel,*argv);
  123.               debuglevel= 1;
  124.             }
  125.           }
  126.           else
  127.           { echo("missing debug level after `%s' option.",*argv);
  128.             ++badopt;
  129.           }
  130. #else
  131.           echo("not compiled w/ -DDEBUG.  No debug information available -- Sorry.");
  132.           /* no error */
  133.  
  134. #endif /* DEBUG */
  135.  
  136.           break;
  137.  
  138. /*-E*/  case 'E':
  139.           if(arg[1]) ++arg;
  140.           else arg= (--argc > 0) ? *(++argv) : (char *)0L;
  141.  
  142.           if(arg && *arg)
  143.           { if(errfile)
  144.             { echo("option `%s' has already been seen!",*argv);
  145.               echo("more than one error filename in your command line");
  146.               ++badopt;
  147.             }
  148.             else errfile= arg;
  149.           }
  150.           else
  151.           { echo("missing filename after `%s' option",*argv);
  152.             ++badopt;
  153.           }
  154.           break;
  155.  
  156. /*-e*/  case 'e':
  157.           if(arg[1]) ++arg;
  158.           else arg= (--argc > 0) ? *(++argv) : (char *)0L;
  159.  
  160.           if(arg && *arg)
  161.           { int e= atoi(arg);
  162.             if(0<e) global_maxerrors= e;
  163.             else echo("illegal maximum #of errors: %d"
  164.                        " (using `-e%d')",e,global_maxerrors);
  165.           }
  166.           else
  167.           { echo("missing maximum #of errors after `%s' option",*argv);
  168.             ++badopt;
  169.           }
  170.           break;
  171.  
  172. /*-f*/  case 'f':
  173.           if(arg[1]) ++arg;
  174.           else arg= (--argc > 0) ? *(++argv) : (char *)0L;
  175.  
  176.           if(arg && *arg)
  177.           { if(rulefile)
  178.             { echo("option `%s' has already been seen!",*argv);
  179.               echo("more than one script filename in your command line");
  180.               ++badopt;
  181.             }
  182.             else rulefile= arg;
  183.           }
  184.           else
  185.           { echo("missing filename after `%s' option",*argv);
  186.             ++badopt;
  187.           }
  188.           break;
  189.  
  190. /*-?*/  case '?':
  191. /*-h*/  case 'h':
  192.           fprintf(stderr,
  193.             "usage: %s [options] [-f rulefile] [-o outfile] [infiles]\n\n",
  194.             whoami);
  195.  
  196.           display_args();
  197.           badopt= 1; /* hack: means exit. */
  198.           break;
  199.  
  200. /*-l*/  case 'l':
  201.           if(arg[1]) ++arg;
  202.           else arg= (--argc > 0) ? *(++argv) : (char *)0L;
  203.  
  204.           if(arg && *arg)
  205.           {
  206.             if( read_flist(arg) != 0)
  207.               ++badopt;
  208.           }
  209.           else
  210.           { echo("missing filename after `%s' option",*argv);
  211.             ++badopt;
  212.           }
  213.           break;
  214.  
  215. /*-n*/  case 'n':
  216.           dryrun= 1;
  217.           break;
  218.  
  219. /*-o*/  case 'o':
  220.           if(arg[1]) ++arg;
  221.           else arg= (--argc > 0) ? *(++argv) : (char *)0L;
  222.  
  223.           if(arg && *arg)
  224.           {
  225.             if(outfmt)
  226.             { echo("option `%s' has already been seen!",*argv);
  227.               echo("more than one output filename in your command line");
  228.               ++badopt;
  229.             }
  230.             else outfmt= arg;
  231.           }
  232.           else
  233.           { echo("missing output filename after `%s' option",*argv);
  234.             ++badopt;
  235.           }
  236.           break;
  237.  
  238. /*-s*/  case 's':
  239.           silent= 1;
  240.           break;
  241.  
  242. /*-t*/  case 't':
  243.           if(arg[1]) ++arg;
  244.           else arg= (--argc > 0) ? *(++argv) : (char *)0L;
  245.  
  246.           if(arg && *arg)
  247.           { if(tmpfile)
  248.             { echo("option `%s' has already been seen!",*argv);
  249.               echo("more than one temporary output filename in your command line");
  250.               ++badopt;
  251.             }
  252.             else
  253.             { if( tmpfile= (char *)malloc((strlen(arg)+1) * sizeof(char)) )
  254.                 strcpy(tmpfile,arg);
  255.               else
  256.               { echo("out of memory... aaaiiiiiieeeeeeeee!");
  257.                 badopt= 103;
  258.               }
  259.             }
  260.           }
  261.           else
  262.           { echo("missing filename after `%s' option",*argv);
  263.             ++badopt;
  264.           }
  265.           break;
  266.  
  267. /*-v*/  case 'v':
  268.           display_version_information();
  269.           break;
  270.  
  271. /*-x*/  case 'x':
  272.           global_checkexists= 1;
  273.           break;
  274.  
  275. /*??*/  default:
  276.           echo("unrecognized option `%s'",*argv);
  277.           badopt++;
  278.           break;
  279.       }
  280.     }
  281.     else if(*arg=='@')
  282.     {
  283.       if(arg[1]) ++arg;
  284.       else arg= (--argc > 0) ? *(++argv) : (char *)0L;
  285.  
  286.       if(arg && *arg)
  287.       {
  288.         if( read_flist(arg) != 0)
  289.           ++badopt;
  290.       }
  291.       else
  292.       { echo("missing filename after `%s'",*argv);
  293.         ++badopt;
  294.       }
  295.     }
  296.     else
  297.     {
  298.       if(global_checkexists)
  299.       {
  300.         FILE *fp= fopen(arg,"r");
  301.  
  302.         if(fp)
  303.           fclose(fp);
  304.  
  305.         else
  306.         { perror(arg);
  307.           ++badopt;
  308.         }
  309.       }
  310.  
  311.       if(!badopt)
  312.       {
  313.         if( chain_fname(0L,arg) )
  314.         {
  315.           echo("out of memory... bzzzzzzzz!");
  316.           ++badopt;
  317.         }
  318.       }
  319.     }
  320.   }
  321.  
  322.   if(!badopt)
  323.   {
  324.     FILE *fp;
  325.  
  326. #ifdef DEBUG
  327.     if(debuglevel >= 1)
  328.       print_flist();
  329. #endif
  330.  
  331.     /*
  332.      * open error stream
  333.      */
  334.  
  335.     if(errfile)
  336.     {
  337.       if( !(ferr= fopen(errfile,"w")) )
  338.       { perror(errfile);
  339.         echo("can't direct error output to `%s' -- will use stderr",
  340.           errfile);
  341.         ferr= stderr;
  342.       }
  343.     }
  344.  
  345.     err= init_rules();
  346.  
  347.     if(!err)
  348.     {
  349.       /*
  350.        * In --dryrun mode the explicit use of the --file keyword
  351.        * is not needed.  Instead we treat all input files as script
  352.        * files and try to parse them respectively.
  353.        * If however there was a --file <rulefile> in the command-line
  354.        * we will ignore futher input files (if any).
  355.        */
  356.  
  357.       if(dryrun)
  358.       {
  359.         if(rulefile)
  360.         {
  361.  
  362. #ifdef DEBUG
  363.           if(flist) /* global_numfiles is >= 1 */
  364.           { echo("debug-warning: %d input files ignored.\n"
  365.                    "(They make no sense w/ options --dryrun --file \"%s\")",
  366.               global_numfiles, rulefile );
  367.           }
  368. #endif /* DEBUG */
  369.  
  370.           if( fp= cvtopen(rulefile) )
  371.           {
  372.             err= parsefile(fp);
  373.             fclose(fp);
  374.           }
  375.           else perror(rulefile);
  376.         }
  377.         else /* !rulefile */
  378.         {
  379.           if(flist) /* global_numfiles is >= 1 */
  380.           {
  381.             fnode_t *fn;
  382.  
  383.             for(fn= flist; fn && !err; fn= fn->next)
  384.             {
  385.               if( fp= cvtopen(rulefile= fn->filename) )
  386.               {
  387.                 err= parsefile(fp);
  388.                 fclose(fp);
  389.  
  390.                 if(!err && fn->next)
  391.                 {
  392.                   fprintf(ferr, "%s: %d rules, no errors.\n",
  393.                     rulefile, global_numrules);
  394.  
  395.                   exit_rules();
  396.                   err= init_rules();
  397.                 }
  398.               }
  399.               else err++;
  400.             }
  401.           }
  402.           else /* !flist */
  403.           { rulefile= "stdin";  /* filename for messages */
  404.             err= parsefile(stdin);
  405.           }
  406.         }
  407.       }
  408.       else /* !dryrun */
  409.       {
  410.         if(rulefile)
  411.           fp= cvtopen(rulefile);
  412.         else
  413.         { echo("warning: no conversion file... copying...");
  414.           fp= (FILE *)0L;
  415.         }
  416.  
  417.         if(fp)
  418.         {
  419.           err= parsefile(fp);
  420.  
  421.           if(fp!=stdin)
  422.             fclose(fp);
  423.  
  424.           if(!err)
  425.           {
  426. #ifdef DEBUG
  427.             if(debuglevel >= 3)
  428.               dump_crules();
  429. #endif
  430.             if(global_numrules==0)
  431.             { echo("warning: file '%s' contains no rules... copying...",
  432.                 rulefile);
  433.             }
  434.           }
  435.         }
  436.         else if(rulefile)
  437.         { echo("no conversion file similar or equal to `%s' -- Sorry.",
  438.             rulefile);
  439.           err= 1;
  440.         }
  441.       }
  442.     }
  443.     else
  444.     { echo("not enough memory for a %d character charset!", global_numchars);
  445.       err= 1;
  446.     }
  447.   }
  448.   else /* badopt != 0 */
  449.     err= 1;
  450.  
  451.   /*
  452.    *  convert
  453.    */
  454.  
  455.   fn= flist;
  456.  
  457.   if(!dryrun && !err) do
  458.   {
  459.     char *infile, *outfile= (char *)0L;
  460.  
  461.     if(fn)
  462.     {
  463.       infile= fn->filename;
  464.  
  465.       if( !(fin= fopen(infile,"rb")) )
  466.       { perror(infile);
  467.         echo("can't access your input file `%s'",infile);
  468.         err= 1;
  469.       }
  470.     }
  471.     else
  472.     { infile= "stdin";
  473.       fin= stdin;
  474.     }
  475.  
  476.     if(!err)
  477.     {
  478.       if(outfmt)
  479.       {
  480.         outfile= (char *)malloc(strlen(infile)+strlen(outfmt));
  481.  
  482.         if(!tmpfile)
  483.           tmpfile= tfname(TEMPFILE_FORMAT);
  484.  
  485.         if(!outfile || !tmpfile)
  486.         {
  487.           echo("out of memory... aaaaarrrgggghhhh!");
  488.           err= 1;
  489.         }
  490.         else
  491.         {
  492.           sprintf(outfile,outfmt,infile);
  493.  
  494.           if(!silent)
  495.             printf("  %s\n",outfile);
  496.  
  497. #ifdef DEBUG
  498.           if(debuglevel >= 1)
  499.             printf("%d chars for output filename `%s' allocated,\n"
  500.                    "writing temporary data on `%s'.\n",
  501.               strlen(infile)+strlen(outfmt), outfile, tmpfile);
  502. #endif /* DEBUG */
  503.         }
  504.       }
  505.       else outfile= (char *)0L; /* use stdout */
  506.  
  507.       /* Wenn wir nach stdout konvertieren sollen, dann brauchen wir
  508.        * kein tempor"ares File, denn wenn wir an die console schicken
  509.        * machen wir eh' nix kaputt und wenn 'stdin' redirected ist,
  510.        * hat die Shell das File auch schon zerschossen...
  511.        * Wir tun dem Benutzer aber den Gefallen und puffern die Ausgabe
  512.        * trotzdem, wenn er es explizit (mittels `-t' Option) w"unscht. */
  513.  
  514.       if(!err && tmpfile)
  515.       {
  516.         if( !(fout= fopen(tmpfile, "wb")) )
  517.         { perror(tmpfile);
  518.           echo("can't access temporary output file `%s'",tmpfile);
  519.           err= 1;
  520.         }
  521.       }
  522.     }
  523.  
  524.     if(!err)
  525.       dothehardpart(); /* let's roll! */
  526.  
  527.     if(fin && fin!=stdin)
  528.       fclose(fin);
  529.  
  530.     if(fout && fout!=stdout)
  531.       fclose(fout);
  532.  
  533.     if(!err)
  534.     {
  535.       long n;
  536.  
  537.       /* Wenn wir in ein tempor"ares File geschrieben haben, (was immer
  538.        * der Fall ist, wenn wir nicht nach stdout geschrieben haben)
  539.        * dann m"ussen wir jetzt noch kopieren.  Wir k"onnen das tmpfile
  540.        * nicht einfach renamen, weil es nicht im aktuellen Verzeichnis
  541.        * stehen mu\3. */
  542.  
  543.       if(outfile)
  544.       {
  545.         if(fin= fopen(tmpfile,"rb"))
  546.         {
  547.           if(fout= fopen(outfile,"wb"))
  548.           {
  549.             if( (n= filecopy(fin,fout,0L)) < 0L )
  550.             {
  551.               if(n==-1)
  552.               { perror(tmpfile);
  553.                 echo("error reading temporary data from `%s'",tmpfile);
  554.               }
  555.               else
  556.               { perror(outfile);
  557.                 echo("error writing output to `%s'",outfile);
  558.                 echo("temporary output written on `%s'",tmpfile);
  559.               }
  560.               err= 1;
  561.             }
  562. #ifdef DEBUG
  563.             else if(debuglevel >= 1)
  564.               printf("%ld byte(s) of output\n",n);
  565. #endif
  566.             fclose(fout);
  567.           }
  568.           else
  569.           { perror(outfile);
  570.             echo("can't write to `%s'",outfile);
  571.             echo("temporary output written on `%s'",tmpfile);
  572.             err= 1;
  573.           }
  574.           fclose(fin);
  575.         }
  576.         else
  577.         { perror(tmpfile);
  578.           echo("couldn't re-open temporary file `%s'",tmpfile);
  579.           err= 1;
  580.         }
  581.       }
  582.       else if(tmpfile) /* but !outfile */
  583.       {
  584.         FILE *fp;
  585.  
  586.         /* Wir haben in ein tempor"ares File geschrieben und m"ussen die
  587.          * Ausgabe auf die Console umleiten.  Wir machen das Zeichen f"ur
  588.          * Zeichen... */
  589.  
  590.         if( fp= fopen(tmpfile, "rb") )
  591.         { for(n=0; !feof(fp); n++)
  592.           { char c= fgetc(fp);
  593.             if(!feof(fp))
  594.               fputc(c,stdout);
  595.           }
  596.           fclose(fp);
  597.         }
  598.         else
  599.         { perror(tmpfile);
  600.           echo("couldn't re-open temporary file");
  601.           err= 1;
  602.         }
  603.       }
  604.       /* otherwise we wrote to <stdout> directly */
  605.     }
  606.  
  607.     if(tmpfile)
  608.     { if(!err)
  609.         remove(tmpfile);
  610.       free(tmpfile);
  611.       tmpfile= (char *)0L;
  612.     }
  613.  
  614.     if(fn)
  615.       fn= fn->next;
  616.  
  617.     if(outfile)
  618.     { free(outfile);
  619.       outfile= (char *)0L;
  620.     }
  621.  
  622.   } while(fn && !err);
  623.  
  624.   if(err)
  625.   { echo("*** [%s] exit code %d.",
  626.       (rulefile && *rulefile) ? rulefile : "no rules", err);
  627.   }
  628.   else if(dryrun && rulefile)
  629.     fprintf(ferr, "%s: %d rules, no errors.\n",rulefile, global_numrules);
  630.  
  631.   if(flist)
  632.     purge_flist();
  633.  
  634.   if(crules)
  635.     exit_rules();
  636.  
  637.   if(ferr && ferr!=stderr)
  638.     fclose(ferr);
  639.  
  640.   exit(err ? 1:0);
  641. }
  642.